/**
 * scrollBar 组件基类
 * ibio-develop
 * 2009-3-11 14:47
 */
package com.ibio8.components.helpers {
	import flash.display.MovieClip;
	import flash.text.TextField;
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	/**
	 * scrollBar 组件基类。
	 * 
	 * <p>
	 * scroll bar 组件基类。通常由 Flash IDE 库中的 MC 继承此类。
	 * 里面可包含状态按钮 com.ibio8.components.buttons.MCStateButton。
	 * </p>
	 * 
	 * @see com.ibio8.components.helpers.buttons	MCStateButton
	 */
	public class BaseScrollBar extends MovieClip {
		/** 最小的宽度或者高度，因为此类不太可能直接 new，所以这里没有加 static **/
		public var BAR_LEAST:uint = 5;
		/** 每次滚动的平均值（px） **/
		public var DELTA_STEP:uint = 5;
		/** 每次滚动所移动的格数 **/
		public var DELTA_WHEEL:uint = 3;
		/** @private **/
		protected var m_container:MovieClip;
		/** @private **/
		protected var m_bar:MovieClip;
		/** @private **/
		protected var m_bg:MovieClip;
		/** @private **/
		protected var m_prevBtn:MovieClip;
		/** @private **/
		protected var m_nextBtn:MovieClip;
		/** @private **/
		protected var m_target:DisplayObject;
		/** @private **/
		protected var m_mask:MovieClip;
		/** @private **/
		protected var m_isVertical:Boolean;
		/** @private **/
		protected var m_distance:Number;
		/** @private **/
		protected var m_autoBarSize:Boolean = false;
		/** @private **/
		protected var m_oldTargetDot:Number = 0;
		/** @private **/
		protected var m_oldBarX:Number;
		/** @private **/
		protected var m_oldBarY:Number;
		/** @private **/
		protected var m_isDraging:Boolean = false;
		/** @private **/
		protected var m_targetW:Number;
		/** @private **/
		protected var m_targetH:Number;
		/** @private **/
		protected var m_targetText:TextField;
		
		/**
		 * 构造函数
		 * @param	bar			拖动条（String/MovieClip）
		 * @param	bg			背景（String/MovieClip）
		 * @param	prevBtn		向前滚动（String/MovieClip）
		 * @param	nextBtn		向后滚动（String/MovieClip）
		 * @param	container	当前库里的 MC(MovieClip，配合 MCScrollBar 使用)
		 */
		public function BaseScrollBar(bar:Object, bg:Object, prevBtn:Object = null, nextBtn:Object = null, container:MovieClip = null) {
			/**
			 * 如果是直接 new BaseScrollBar，这里没有直接 m_container[bar]
			 * 是因为有可能 bar 会有扩展。
			 */
			//如果是继承库里的 MC
			if (container) {
				m_container = container;
				m_bar = m_container[bar];
				m_bg = m_container[bg];
				m_prevBtn = m_container[prevBtn];
				m_nextBtn = m_container[nextBtn];
			}else {
				m_container = bar.parent;
				m_bar = bar as MovieClip;
				m_bg = bg as MovieClip;
				m_prevBtn = prevBtn as MovieClip;
				m_nextBtn = nextBtn as MovieClip;
			}
			m_bar.buttonMode = true;
			//上下翻页按钮若没有，则置空来容错
			if (m_prevBtn) {
				m_prevBtn.onClick(onPrevClick);
			}else {
				m_prevBtn = new MovieClip();
			}
			if (m_nextBtn) {
				m_nextBtn.onClick(onNextClick);
			}else {
				m_nextBtn = new MovieClip();
			}
			m_bar.addEventListener(MouseEvent.MOUSE_DOWN, barPressHandler);
			m_bg.addEventListener(MouseEvent.MOUSE_DOWN, bgPressHandler);
			m_container.addEventListener(Event.ADDED_TO_STAGE, onContainerAddedHandler);
			m_container.addEventListener(Event.REMOVED_FROM_STAGE, onContainerRemovedHandler);
			m_oldBarX = m_bar.x;
			m_oldBarY = m_bar.y;
		}
		
		/**
		 * 改变 scroll bar 的大小，需要在每次 resize 的时候调用一次
		 * @param	width	新的宽度
		 * @param	height	新的高度
		 */
		public function setSize(width:Number, height:Number):void {
			if (!m_target) {
				return;
			}
			if (m_isVertical) {
				/**
				 * 这里没有同时改变width是因为：在scrollBar实际应用中，
				 * 如果是复用同一个scrollBar，则按钮尺寸应相同，不同的只是轨道而已；
				 * 如果连按钮尺寸也不相同，则应该考虑专为其制作特异scrollBar
				 */
				m_nextBtn.y = height - m_nextBtn.height;
				m_bg.y = m_prevBtn.height;
				m_bg.height = height - m_prevBtn.height - m_nextBtn.height;
			}else {
				m_nextBtn.x = width - m_nextBtn.width;
				m_bg.x = m_prevBtn.width;
				m_bg.width = width - m_prevBtn.width - m_nextBtn.width;
			}
			//
			initSize();
		}
		
		/**
		 * 移动到某个位置
		 * @param	ratio	移动到的比值（0-1）
		 */
		public function scrollToRatio(ratio:Number):void {
			var value:Number;
			if (m_isDraging || (!m_target)) {
				return;
			}
			if (m_isVertical) {
				value = ratio * (m_bg.height - m_bar.height) + m_bg.y;
			}else {
				value = ratio * (m_bg.width - m_bar.width) + m_bg.x;
			}
			changeBarPos(value);
			changeTarget();
		}
		
		/**
		 * 设置需要改变的目标
		 * @param target		需要改变的目标
		 * @param mask			遮罩MC
		 * @param isVertical	是否垂直滚动，默认为是
		 * @param autoBarSize	是否自动改变条的大小，默认为是
		 * @param useWheel		是否启用滚轮，默认为是
		 */
		public function setChangeTarget(target:DisplayObject, mask:MovieClip = null, isVertical:Boolean = true, autoBarSize:Boolean = true, useWheel:Boolean = true):void{
			m_target = target;
			//是否是TextField
			if (m_target is TextField) {
				m_targetText = m_target as TextField;
				m_targetW = m_targetText.textWidth;
				m_targetH = m_targetText.textHeight;
				m_mask = new MovieClip();
				m_mask.x = m_target.x;
				m_mask.y = m_target.y;
				m_target.addEventListener(Event.SCROLL, onTextScrollHandler);
				//这里drawRect来获得准确的宽高
				m_mask.graphics.beginFill(0);
				m_mask.graphics.drawRect(0, 0, m_target.width, m_target.height);
			}else {
				m_targetW = m_target.width;
				m_targetH = m_target.height;
				m_mask = mask;
			}
			m_isVertical = isVertical;
			m_autoBarSize = autoBarSize;
			if (useWheel && m_target.parent) {
				m_target.parent.addEventListener(MouseEvent.MOUSE_WHEEL, onWheelHandler);
			}
			initSize();
		}
		
		/** @private **/
		protected function onMouseMoveHandler(e:MouseEvent):void {
			/**
			 * 这里没有加this.mc_bg.hitTestPoint(m_container.stage.mouseX, m_container.stage.mouseY)
			 * 是因为在当鼠标移动到外面去只要还没有放开就认为是还在移动
			 */
			if (m_isDraging) {
				e.updateAfterEvent();
				changeTarget();
			}
		}
		
		/** @private **/
		protected function barPressHandler(e:MouseEvent):void {
			m_bar.stage.addEventListener(MouseEvent.MOUSE_UP, onReleaseHandler);
			var rect:Rectangle;
			if (m_isVertical) {
				rect = new Rectangle(m_oldBarX, m_bg.y, 0, m_distance);
			}else {
				rect = new Rectangle(m_bg.x, m_oldBarY, m_distance, 0);
			}
			m_bar.startDrag(false, rect);
			m_isDraging = true;
		}
		
		/** @private **/
		protected function onReleaseHandler(e:MouseEvent):void {
			m_bar.stage.removeEventListener(MouseEvent.MOUSE_UP, onReleaseHandler);
			m_bar.stopDrag();
			/**
			 * 更新向前、向后按钮状态
			 * 加m_isDraging的意义：确保只在停止拖拽的时候更新数据，
			 * 以免鼠标点击背景(bgPressHandler)的时候重复更新数据
			 */
			if (m_isDraging) {
				changeBarPos(0, 0, true);
				m_isDraging = false;
			}
		}
		
		/** @private **/
		protected function bgPressHandler(e:MouseEvent):void {
			//如果是在 bg上面或者从 bar上面释放鼠标 则执行更新
			if (m_bg.hitTestPoint(m_container.stage.mouseX, m_container.stage.mouseY)) {
				if (m_isVertical) {
					changeBarPos(m_container.mouseY, m_bar.height / 2);
				}else {
					changeBarPos(m_container.mouseX, m_bar.width / 2);
				}
				changeTarget();
			}
		}
		
		/** @private **/
		protected function onWheelHandler(e:MouseEvent):void {
			if (m_target.hitTestPoint(m_container.stage.mouseX, m_container.stage.mouseY) 	||
				m_bar.hitTestPoint(m_container.stage.mouseX, m_container.stage.mouseY) 		||
				m_bg.hitTestPoint(m_container.stage.mouseX, m_container.stage.mouseY) 		||
				m_prevBtn.hitTestPoint(m_container.stage.mouseX, m_container.stage.mouseY)	||
				m_nextBtn.hitTestPoint(m_container.stage.mouseX, m_container.stage.mouseY)) {
				//因为通常一个滚动滚动 DELTA_WHEEL，所以这里要除以 DELTA_WHEEL
				changeBarPos(-(e.delta / DELTA_WHEEL) * DELTA_STEP, 0, true);
				changeTarget();
			}
		}
		
		/** @private **/
		protected function onTextScrollHandler(e:Event):void {
			var value:Number;
			if (m_isVertical) {
				value = m_targetText.scrollV / m_targetText.maxScrollV * m_distance + m_bg.y;
			}else {
				value = m_targetText.scrollH  / m_targetText.maxScrollH * m_distance + m_bg.x;
			}
			changeBarPos(value);
		}
		
		/** @private **/
		protected function initSize():void {
			var ratio:Number;
			var length:Number;
			//是否是垂直滚动
			if (m_isVertical) {
				m_bar.y = m_bg.y;
				m_oldTargetDot = m_target.y;
				ratio = m_mask.height / m_targetH;
				if (m_autoBarSize) {
					length = m_mask.height * m_bg.height / m_targetH;
					//rank 保护
					length = (length < m_bg.height) ? length : m_bg.height;
					m_bar.height = (length >= BAR_LEAST) ? Math.round(length) : BAR_LEAST;
				}
			}else {
				m_bar.x = m_bg.x;
				m_oldTargetDot = m_target.x;
				ratio = m_mask.width / m_targetW;
				if (m_autoBarSize) {
					length = m_mask.width * m_bg.width / m_targetW;
					length = (length < m_bg.width) ? length : m_bg.width;
					m_bar.width = (length >= BAR_LEAST) ? Math.round(length) : BAR_LEAST;
				}
			}
			if(ratio < 1 && ratio > 0){
				m_bar.visible = true;
				//bar实际移动的距离
				if (m_isVertical) {
					m_distance = m_bg.height - m_bar.height;
				}else {
					m_distance = m_bg.width - m_bar.width;
				}
				//更新向前、向后按钮状态
				changeBarPos(0, 0, true);
			}else{
				m_bar.visible = false;
				m_prevBtn.enabled = false;
				m_nextBtn.enabled = false;
			}
		}
		
		/** @private **/
		protected function onPrevClick():void {
			changeBarPos(-DELTA_STEP, 0, true);
			changeTarget();
		}
		
		/** @private **/
		protected function onNextClick():void{
			changeBarPos(DELTA_STEP, 0, true);
			changeTarget();
		}
		
		/** @private **/
		protected function changeBarPos(value:Number, delta:Number = 0, isIncrement:Boolean = false):void {
			if (!m_bar.visible) {
				return;
			}
			m_prevBtn.enabled = true;
			m_nextBtn.enabled = true;
			if (m_isVertical) {
				//是否是增量增加
				value = isIncrement ? (m_bar.y + value) : value;
				//delta表示在bar上偏移的量
				if (value <= (m_bg.y + delta)) {
					//注意：startDrag 移动有可能只对整数有效，所以这里用了 Math.round 来确保为整数
					m_bar.y = Math.round(m_bg.y);
					m_prevBtn.enabled = false;
				}else if (value >= (m_distance + delta + m_bg.y)) {
					m_bar.y = Math.round(m_distance + m_bg.y);
					m_nextBtn.enabled = false;
				}else {
					m_bar.y = Math.round(value - delta);
				}
			}else {
				value = isIncrement ? (m_bar.x + value) : value;
				if (value <= (m_bg.x + delta)) {
					m_bar.x = Math.round(m_bg.x);
					m_prevBtn.enabled = false;
				}else if (value >= (m_distance + delta + m_bg.x)) {
					m_bar.x = Math.round(m_distance + m_bg.x);
					m_nextBtn.enabled = false;
				}else {
					m_bar.x = Math.round(value - delta);
				}
			}
		}
		
		/** @private **/
		protected function changeTarget():void {
			if (!m_bar.visible) {
				return;
			}
			var ratio:Number;
			/**
			 * 这里的算法是：
			 * -（移动MC总高度 - 显示区域高度）*当前bar相对于bg的百分比 + 原始的移动MC的位置
			 */
			if (m_isVertical) {
				ratio = (m_bar.y - m_bg.y) / m_distance;
				if ((Number(ratio) >= 0) && (Number(ratio) <= 1)) {
					if (m_target is TextField) {
						m_targetText.scrollV = Math.round(ratio * m_targetText.maxScrollV);
					}else {
						m_target.y = -(m_target.height - m_mask.height) * ratio + m_oldTargetDot;
					}
				}
			}else {
				ratio = (m_bar.x - m_bg.x) / m_distance;
				if ((Number(ratio) >= 0) && (Number(ratio) <= 1)) {
					if (m_target is TextField) {
						m_targetText.scrollH = Math.round(ratio * m_targetText.maxScrollH);
					}else {
						m_target.x = -(m_target.width - m_mask.width) * ratio + m_oldTargetDot;
					}
				}
			}
		}
		
		/** @private **/
		protected function onContainerAddedHandler(e:Event):void {
			m_container.stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMoveHandler);
			m_container.removeEventListener(Event.ADDED_TO_STAGE, onContainerAddedHandler);
		}
		
		/** @private **/
		protected function onContainerRemovedHandler(e:Event):void {
			m_bar.removeEventListener(MouseEvent.MOUSE_DOWN, barPressHandler);
			m_bg.removeEventListener(MouseEvent.MOUSE_DOWN, bgPressHandler);
			m_container.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMoveHandler);
			m_bar.stage.removeEventListener(MouseEvent.MOUSE_UP, onReleaseHandler);
			m_container.removeEventListener(Event.REMOVED_FROM_STAGE, onContainerRemovedHandler);
			if (m_target && m_target.parent) {
				m_target.parent.removeEventListener(MouseEvent.MOUSE_WHEEL, onWheelHandler);
			}
			if (m_target is TextField) {
				m_target.removeEventListener(Event.SCROLL, onTextScrollHandler);
			}
		}
	}
}